#ifndef DEVICE_INCLUDE
#define DEVICE_INCLUDE

#include <string>
#include <tuple>
#include <memory>
#include <mutex>
#include <atomic>
#include "eXosip2/eXosip.h"

#include <iostream>
#include <cstdlib>
#include <vector>
#include <condition_variable>
#include <unordered_set>
#include "nalu.h"

extern "C" {   
    #include <libavformat/avformat.h> // avformat.h：处理多媒体容器格式
    #include <libavcodec/avcodec.h>   // avcodec.h：编解码器相关功能
    #include <libswscale/swscale.h>   // swscale.h：图像缩放和色彩空间转换
    #include <libavutil/imgutils.h>   // imgutils.h：图像处理工具函数
    #include <libavutil/opt.h>        // opt.h：选项解析工具
    #include <libavutil/log.h>        // log.h：日志记录工具
}


using namespace std;

class Device {
public:
    Device() {}
    Device(string server_sip_id, string server_ip, int server_port,
            string device_sip_id, string username, string password,
            int local_port,
            string manufacture,
            string filepath): 
            server_sip_id(server_sip_id), 
            server_ip(server_ip),
            server_port(server_port),
            device_sip_id(device_sip_id),
            username(username),
            password(password),
            local_port(local_port),
            manufacture(manufacture),
            filepath(filepath) {
            sip_context = nullptr;
            is_running = false;
            is_register = false;
            local_ip = string(128, '0');

        // load(filepath.c_str());
        // int ret =  h265_parser(filepath.c_str(),nalu_vector);
        // if(!ret){
        //     std::cout<<"解析失败"<<std::endl;
        // }
    }

    ~Device(){
        
    }
    /////////////////////////////////////////////
    /// 设备启停
    ////////////////////////////////////////////
    void start();
    void stop();

    /////////////////////////////////////////////
    /// 信令处理
    ////////////////////////////////////////////
    void process_request();
    void process_catalog_query(string sn);
    void process_deviceinfo_query(string sn);
    void process_devicestatus_query(string sn);
    void process_devicecontrol_query(string sn);
    // 心跳维持
    void heartbeat_task();
    void send_request(osip_message_t * request);
    void send_response(shared_ptr<eXosip_event_t> evt, osip_message_t * msg);
    osip_message_t * create_msg();
    void send_response_ok(shared_ptr<eXosip_event_t> evt);
    std::tuple<string, string> get_cmd(const char * body);
    // 推送RTP包
    void push_rtp_stream();

    //////////////////////////////////////////////////
    /// RTSP拉流 GB28182平台推流
    //////////////////////////////////////////////////
    void set_ffmpeg_log_level();
    // 从AVPacket包中提取NALU
    void process_packet(AVPacket *pkt);
    // 分析出NALU的类型
    NaluType parse_nalu_type(uint8_t *nalu); 
    // 处理NALU, 根据H265编码格式对NALU进行封装，并推送到GB28181平台
    void handle_nalu(uint8_t* nalu_data, int nalu_size, NaluType nalu_type, int64_t pts, int64_t dts);
    // 处理H265编码的流地址
    int h265_parser(const char *url,std::vector<Nalu *> &nalu_vector);

private:

    //////////////////////////////////////////
    /// 关键帧枚举判断
    //////////////////////////////////////////
    static const std::unordered_set<NaluType> KEYFRAME_TYPES;
    bool is_keyframe(NaluType type) const {
        return KEYFRAME_TYPES.find(type) != KEYFRAME_TYPES.end();
    }

public:
    string server_sip_id;
    string server_ip;
    int server_port;
    string device_sip_id;
    string username;
    string password;
    string local_ip;
    int local_port;

    string manufacture;
    string rtp_ip;
    int rtp_port;
    string rtp_protocol;

    string filepath;
    std::vector<Nalu *> nalu_vector;  // 用于存储NALU - h265编码格式(如果测试本地文件推流需要关闭)
    std::mutex nalu_mutex;
    std::condition_variable nalu_cond;

public:
    // 升级到线程安全
    std::atomic<bool> is_pushing;
    std::atomic<bool> is_register;
    std::atomic<bool> is_running;

private:
    std::vector<uint8_t> vps_data;  // 缓存 VPS
    std::vector<uint8_t> sps_data;  // 缓存 SPS
    std::vector<uint8_t> pps_data;  // 缓存 PPS
private:
    eXosip_t* sip_context;
    string from_sip;
    string to_sip;
    string ssrc;

    int sockfd;
    int bind();
    void send_network_packet(const char * data, int length);
};

#endif
